#include "tcpclient.h"

QList<QList<QString>>IpAndHostName;
QMap<QString,QString>Map_AvoidReopenWidgets;

TcpClient::TcpClient(const QString &addr, const quint16 &port, QObject *parent):QTcpSocket(parent),
    var_ip(addr),var_port(port),var_packetReceiveSize(0),var_fileBytesRecv(0),
    var_dataBytesRecv(0),var_isCompletepacket(true)
{
    setReadBufferSize(READ_BUFFER); // 系统默认最大容量为65535个字节
    connect(this,&TcpClient::readyRead,this,&TcpClient::readyReceive);
    connect(this,&TcpClient::bytesWritten,this,&TcpClient::readySend);
    connect(this,&TcpClient::stateChanged,this,&TcpClient::tcpStateChange);
}

TcpClient::~TcpClient()
{
    qDebug() << "~~~~TCP Client 析构";
}

void TcpClient::tcpStateChange()
{
    emit tcpStateChanged(state());
}

void TcpClient::createConnection()
{
    if(state() == QAbstractSocket::UnconnectedState)
    {
        abort();
        connectToHost(var_ip,var_port);
    }
}

void TcpClient::closeConnection()
{
    if(state() == QAbstractSocket::ConnectedState)
    {
        disconnectFromHost();
    }
    else if(state() == QAbstractSocket::ConnectingState)
    {
        emit errorOccurred(QAbstractSocket::SocketTimeoutError);
        abort();
    }
}

bool TcpClient::processDataPacket(qint8 type) // 处理数据包
{
    if(type == TYPE_FILE)
    {
        if(var_fileBytesRecv==0)
        {
            QByteArray tempData = this->read(qint64(sizeof(qint64)) - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == qint64(sizeof(qint64)))
            {
                QDataStream in(&var_tempReceiveData,QIODevice::ReadOnly);
                in >> var_fileTotalBytes;
                var_fileBytesRecv += qint64(sizeof(qint64));
                // 读完一个完整packet后返回
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
            }
            else
            {
                return false;
            }
        }
        if(var_fileBytesRecv>0 && var_fileBytesRecv<qint64(sizeof(qint64)*2))
        {
            QByteArray tempData = this->read(qint64(sizeof(qint64)) - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == qint64(sizeof(qint64)))
            {
                QDataStream inBlock(&var_tempReceiveData,QIODevice::ReadOnly);
                inBlock >> var_fileNameSize;
                var_fileBytesRecv += qint64(sizeof(qint64));
                // 读完一个完整packet后返回
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
            }
            else
            {
                return false;
            }
        }
        if(var_fileBytesRecv>=qint64(sizeof(qint64)*2) && var_fileBytesRecv<qint64(sizeof(qint64)*2)+var_fileNameSize)
        {
            QByteArray tempData = this->read(var_fileNameSize - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == var_fileNameSize)
            {
                QDataStream inBlock(&var_tempReceiveData,QIODevice::ReadOnly);
                inBlock >> var_fileName;
                var_fileBytesRecv += var_fileNameSize;
                var_newFiles.setFileName(var_filePath+var_fileName);
                if(!var_newFiles.open(QIODevice::WriteOnly))
                {
                    qErrnoWarning("file open failed");
                    return false;
                }
                // 读完一个完整packet后返回
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
                return true;
            }
            else
            {
                return false;
            }
        }
        if(var_newFiles.isOpen())
        {
            if(var_fileTotalBytes-var_fileBytesRecv>=qint64(PAYLOADSIZE))
            {
                QByteArray tempData = this->read(qint64(PAYLOADSIZE) - var_packetReceiveSize);
                var_tempReceiveData.append(tempData);
                var_packetReceiveSize += tempData.size();
                if(var_packetReceiveSize == qint64(PAYLOADSIZE))
                {
                    var_fileBytesRecv += qint64(PAYLOADSIZE);
                    var_newFiles.write(var_tempReceiveData);
                    // 读完一个完整packet后返回
                    var_tempReceiveData.resize(0);
                    var_packetReceiveSize = 0;
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else // 文件数据的最后一个包
            {
                QByteArray tempData = this->read(var_fileTotalBytes - var_fileBytesRecv - var_packetReceiveSize);
                var_tempReceiveData.append(tempData);
                var_packetReceiveSize += tempData.size();
                if(var_packetReceiveSize == var_fileTotalBytes - var_fileBytesRecv)
                {
                    var_fileBytesRecv += var_packetReceiveSize;
                    var_newFiles.write(var_tempReceiveData);
                    // 读完一个完整packet后返回
                    var_tempReceiveData.resize(0);
                    var_packetReceiveSize = 0;
                }
                else
                {
                    return false;
                }
                if(var_fileBytesRecv == var_fileTotalBytes)
                {
                    qDebug() << thread() << ": " << tr("Files 写入完毕"); /////////////////////////// qdebug
                    var_newFiles.close();
                }
                return true;
            }
        }
        return false;
    }
    else if(type == TYPE_DATA)
    {
        if(var_dataBytesRecv == 0)
        {
            QByteArray tempData = this->read(qint64(sizeof(qint64)) - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == qint64(sizeof(qint64)))
            {
                QDataStream inBlock(&var_tempReceiveData,QIODevice::ReadOnly);
                inBlock >> var_dataTotalBytes;
                var_dataBytesRecv += qint64(sizeof(qint64));
                // 读完一个完整packet后返回
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
            }
            else
            {
                return false;
            }
        }
        if(var_dataBytesRecv > 0)
        {
            QByteArray tempData = this->read(var_dataTotalBytes - var_dataBytesRecv - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == var_dataTotalBytes - var_dataBytesRecv)
            {
                QDataStream inBlock(&var_tempReceiveData,QIODevice::ReadOnly);
                QString result;
                inBlock >> result;
                // 显示结果
                emit faultDiagnosisResults(result);
                // 读完一个完整packet后返回
                var_dataBytesRecv = 0;
                var_dataTotalBytes = 0;
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }
    else if(type == TYPE_INFO)
    {
        if(var_dataBytesRecv == 0)
        {
            QByteArray tempData = this->read(qint64(sizeof(qint64)) - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == qint64(sizeof(qint64)))
            {
                QDataStream inBlock(&var_tempReceiveData,QIODevice::ReadOnly);
                inBlock >> var_dataTotalBytes;
                var_dataBytesRecv += qint64(sizeof(qint64));
                // 读完一个完整packet后返回
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
            }
            else
            {
                return false;
            }
        }
        if(var_dataBytesRecv > 0)
        {
            QByteArray tempData = this->read(var_dataTotalBytes - var_dataBytesRecv - var_packetReceiveSize);
            var_tempReceiveData.append(tempData);
            var_packetReceiveSize += tempData.size();
            if(var_packetReceiveSize == var_dataTotalBytes - var_dataBytesRecv)
            {
                QDataStream inBlock(&var_tempReceiveData,QIODevice::ReadOnly);
                QString info;
                inBlock >> info;
                // 显示结果
                emit serverInformation(info);
                // 读完一个完整packet后返回
                var_dataBytesRecv = 0;
                var_dataTotalBytes = 0;
                var_tempReceiveData.resize(0);
                var_packetReceiveSize = 0;
                return true;
            }
            else
            {
                return false;
            }
        }
        return false;
    }
    return false;
}

void TcpClient::dataCollection(const qint64 cmd, QString path) //通过mainwindow信号驱动
{
    var_filePath = path;
    sendCommand(cmd);
}

void TcpClient::readyReceive()
{
    QDataStream in(this); //没有">>"操作，就没有把数据取出来，所以就算销毁in对象，数据也会存在buffer中
    in.setVersion(QDataStream::Qt_6_9);
    while(!in.atEnd())
    {
        if(var_isCompletepacket)
        {
            in >> var_packetType;
            var_isCompletepacket = processDataPacket(var_packetType); // 返回true则处理一个完整的包
            if(!var_isCompletepacket) // 如果数据不够，重新获取缓冲区数据
                break;
        }
        else
        {
            var_isCompletepacket = processDataPacket(var_packetType); // 返回false则表明这个包还没接收完整
        }
    }
    // 进度条,速度,剩余大小
    if(var_packetType && var_fileBytesRecv>0)
    {
        float useTime = var_wasteTime.elapsed();
        float speed = var_fileBytesRecv / useTime;
        float receiveSize = var_fileBytesRecv;
        float totalSize = var_fileTotalBytes;
        emit dataCollectionProgress(speed,receiveSize,totalSize);
    }
    else
    {
        var_wasteTime.restart();
    }
}

void TcpClient::sendCommand(qint64 cmd)
{
    if(cmd == cmd_dataCollectionStart)
    {
        var_cmd = cmd_dataCollectionStart;
        var_fileBytesRecv = 0;
        var_fileTotalBytes = 0;
    }
    else if(cmd == cmd_dataCollectionStop)
    {
        var_cmd = cmd_dataCollectionStop;
        var_wasteTime.start();
    }
    else if(cmd == cmd_faultDiagnosis)
    {
        var_cmd = cmd_faultDiagnosis;
    }
    else if(cmd == cmd_stopTransmition)
    {
        var_cmd = cmd_stopTransmition;
    }
    QByteArray outblock;
    QDataStream out(&outblock,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_9);
    out << qint8(TYPE_CMD) << var_cmd;
    write(outblock);
}

void TcpClient::readySend()
{

}

//-------------------------UDP------------------------------//
udpClient::udpClient(QObject *parent):QUdpSocket(parent)
{
    if(!bind(UDP_CLIENT_PORT))
        flag = false;
    else
        flag = true;
    connect(this,&udpClient::readyRead,this,&udpClient::readPendingDatagrams);
    connect(this,&udpClient::bytesWritten,this,&udpClient::sendPendingDatagrams);
    connect(this,&udpClient::errorOccurred,this,&udpClient::errorOccur);
}

udpClient::~udpClient()
{

}

bool udpClient::isSuccessfullyOpen()
{
    return flag;
}

void udpClient::readPendingDatagrams()
{
    while(hasPendingDatagrams())
    {
        QNetworkDatagram datagrams = receiveDatagram(pendingDatagramSize());
        if(datagrams.isValid())
        {
            QByteArray inblock = datagrams.data();
            qDebug() << "client udp:" << inblock.size();
            if(inblock.size() != sizeof(cmd_sendIpAndHostName))
            {
                QDataStream in(&inblock,QIODevice::ReadOnly);
                in.setVersion(QDataStream::Qt_6_9);
                in >> var_IpAddress >> var_HostName;
                IpAndHostName.append(QList<QString>() << var_IpAddress << var_HostName);
                emit getIpAndName();
            }
        }
    }
}

void udpClient::sendCommand()
{
    QByteArray outblock;
    QDataStream out(&outblock,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_6_9);
    out << cmd_sendIpAndHostName;
    writeDatagram(outblock,QHostAddress::Broadcast,UDP_SERVER_PORT);

    IpAndHostName.resize(0);
}

void udpClient::sendPendingDatagrams()
{
    // qDebug("------------>sendPendingDatagrams");
}

void udpClient::errorOccur()
{
    emit textLabel("UDP Error:"+errorString()); /////////////////////////// qdebug
    qDebug() << "UDP Error: " << errorString();
}
